package com.sync.utils.project.demo.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.sync.utils.project.demo.pojo.OrderDelayed;
import com.sync.utils.project.demo.service.PollingOrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;

/**
 * TODO
 *
 * @Author YWF
 * @Date 2023/6/20 17:47
 */
@Slf4j
@Service
public class PollingOrderServiceImpl implements PollingOrderService {

    private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(20,100,10, TimeUnit.SECONDS,new ArrayBlockingQueue<>(1000),new ThreadPoolExecutor.DiscardOldestPolicy());

    private final static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:sss");

    @Override
    public Map<String,String> pollingOrder(Map<String, String> order) {
        Map<String,String> orderResult = new HashMap();
        try {
            // 创建延时队列
            // 每隔3秒钟执行一次 先执行20次
            // 90秒钟的时候轮询一次
            // 120秒钟的时候轮询一次
            // 180秒钟的时候轮询一次
            // 300秒钟的时候轮询一次
            // 10分钟的时候轮询一次
            //执行具体的业务方法
            // 如果拿到终态（达到目标），直接break，退出轮询
            checkThreadPool();//动态调整线程池
            Future<Map> s = threadPoolExecutor.submit(new Callable<Map>() {
                String orderNo = order.get("orderNo");
                @Override
                public Map call() {
                    try {
                        // 创建延时队列
                        DelayQueue<OrderDelayed> queue = new DelayQueue<>();
                        // 每隔3秒钟执行一次 先执行20次
                        for (int i = 0; i < 20; i++) {
                            OrderDelayed orderDelayed = new OrderDelayed(orderNo, 3 * (i + 1), TimeUnit.SECONDS);
                            queue.put(orderDelayed);
                        }
                        //90,120,180,300,10分钟的时候轮询一次
                        long[] longArr = {90,120,180,300,60*10};
                        for (long lArr : longArr) {
                            OrderDelayed orderDelayed = new OrderDelayed(orderNo, lArr, TimeUnit.SECONDS);
                            queue.put(orderDelayed);
                        }
                        int size = queue.size();
                        for (int i = 0; i < size; i++) {
                            OrderDelayed orderDelayed = queue.take();
                            log.info("订单号【{}】的付款订单，第{}次轮询,任务名称【{}】,当前时间{}", orderDelayed.getOrderNo(), (i + 1),orderDelayed.getTaskName(), DateUtil.format(DateTime.now(), format));
                            //执行具体的业务方法
                            // 如果拿到终态（达到目标），直接break，退出轮询
                            if (i == 30) {
                                log.info("订单号【{}】的付款订单,获取订单结果成功", orderDelayed.getOrderNo());
                                orderResult.put("orderStatus", "Completed");
                                orderResult.put("orderNo", orderDelayed.getOrderNo());
                                orderResult.put("pollCounts", String.valueOf(i + 1));
                                break;
                            }
                        }
                        checkThreadPool();//动态调整线程池
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    return orderResult;
                }
            });
            Map result = null; //s.get();
            return result;
        }catch (Exception e) {
            log.info("轮询订单交易结果异常", e);
        }
        return orderResult;
    }

    /**
     * @Author read
     * @Description 检查并动态调整线程池
     * 基本思路：
     * 1、以较小的核心线程数初始化，避免占用太多空闲资源；
     * 2、业务量初步增长的时候动态扩张核心线程数，避免任务过早进入队列导致响应慢；（业务量大时增加并发处理能力）
     * 3、业务量异常激增超过最大线程数时，此时线程池满负荷工作，超出的任务进入队列等待处理；（变相实现服务降级）
     * 4、业务量下降时动态缩容核心线程数，避免过多资源浪费；
     * @Date 23:50 2020/12/22
     * @Param []
     * @return void
     **/
    public void checkThreadPool() {
        int activeCount = threadPoolExecutor.getActiveCount();
        int corePoolSize = threadPoolExecutor.getCorePoolSize();
        int maximumPoolSize = threadPoolExecutor.getMaximumPoolSize();
        int usedSize = threadPoolExecutor.getQueue().size();
        log.info("负责轮询的线程池活动线程数{}，核心线程数{}，最大线程数{}，队列任务数{}", activeCount, corePoolSize, maximumPoolSize, usedSize);

        if ((activeCount > corePoolSize - 10) && (corePoolSize + 10 < maximumPoolSize)) {
            threadPoolExecutor.setCorePoolSize(corePoolSize + 10);
            log.info("负责轮询的线程池核心线程数扩容10");
        }
        if (activeCount < corePoolSize - 25) {
            threadPoolExecutor.setCorePoolSize(corePoolSize - 10);
            log.info("负责轮询的线程池核心线程数缩容10");
        }
    }



}
